<?php

declare(strict_types=1);

namespace App\Middleware;

use App\Constants\Cache;
use App\Constants\Config;
use App\Constants\Constants;
use App\Constants\Tip;
use App\Exception\ResponseException;
use App\Kernel\Utils\JwtInstance;

use App\Service\Dao\UserBanRecordDao;
use Hyperf\Context\Context;
use Hyperf\Contract\TranslatorInterface;
use Hyperf\HttpServer\Router\Dispatched;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Swoole\Coroutine;

class AuthMiddleware implements MiddlewareInterface
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $dispatched = $request->getAttribute(Dispatched::class);
        if ($dispatched->handler === null) {
            throw new ResponseException('', 10106);
        }
        Context::set(Constants::CONTEXT_MARKET_ID, $request->getHeaderLine(Constants::REQUEST_MARKET));
        Context::set('REQUEST_TIME', getMillisecond());

//        Context::set(Constants::CONTEXT_MARKET_ID, 2);
        // 需要对内容的token进行验证偏移
        $route = $dispatched->handler->route;
        if (in_array($route, Constants::NEED_CHECK_IP, true)) {
            if ((int)$this->container->get(Redis::class)->zScore(Cache::CACHE_IP_BLACK_POOL, (string)getIpAddress(true)) > time()) {
                throw new ResponseException('', 10100);
            }
        }

        if (!in_array($route, Constants::REQUEST_DECRYPT_WHITE_LIST, true)) {
            $this->verifyRequest($request, $route);
        }
        Context::set(Constants::CONTEXT_ROUTE, $route);
        // 跳过白名单
        if (in_array($route, Constants::AUTH_WHITE_LIST, true)) {
            return $handler->handle($request);
        }
        // 获取token
        $token = $request->getHeaderLine(Constants::AUTHORIZATION);
        if (empty($token)) {
            throw new ResponseException('', 10104);
        }

        $user = JwtInstance::instance()->decode($token)->getUser();
        // 判断用户状态
        if (empty($user)) {
            throw new ResponseException('',10102);
        }
        if ($user->status == 2) {
            if (time() < strtotime($user->login_forbid_expire)) {
                $banRecord = $this->container->get(UserBanRecordDao::class)->find($user->id);
                Context::set(Constants::CONTEXT_ERROR_ARG, [
                    'number' => empty($user->special_id) ? $user->show_number : $user->special_id,
                    'reason' => __('business.' . $banRecord->reason ?? ''),
                    'time' => $user->login_forbid_expire,
                ]);
                throw new ResponseException('',20206);
            }
        }
        if ($user->status == 3) {
            throw new ResponseException(20209);
        }
        $uid = $request->getHeaderLine(Constants::REQUEST_UID);
        if($user->id != $uid && !in_array($route, Constants::H5_ROUTER)) {
            throw new ResponseException('',10133);
        }

        Context::set(Constants::IS_EXAMINE_ENV, isExamineEnv($user->id));
        if ($user->group_flg == 3) {
            Context::set(Constants::CUSTOMER_SERVICE_DIALOG, true);
        }
        Context::set(Constants::CONTEXT_USER, $user);
        Context::set(Constants::CONTEXT_USER_ID, $user->id);
        Context::set(Constants::CONTEXT_AGENT_ID, $user->agent_id);
        Context::set(Constants::CONTEXT_USER_TYPE, getUserType($user->create_time));
        // 包标识
        $packageMark = (int)$request->getHeaderLine(Constants::REQUEST_PACKAGE_MARK);
        Context::set(Constants::CONTEXT_PACKAGE_ID, empty($packageMark) ? 1 : $packageMark);
        Context::set('device_type', $request->getHeaderLine(Constants::REQUEST_DEVICE_TYPE));
        return $handler->handle($request);
    }

    /**
     * 验证请求
     */
    public function verifyRequest(ServerRequestInterface $request, string $router)
    {
        if (env('APP_ENV') == 'dev') {
            $whiteAuth = $request->getHeaderLine(Constants::REQUEST_WHITE_TOKEN);
            if ($whiteAuth == env('AUTH_REQUEST_WHITE_TOKEN')) {
                Context::set('white_token', true);
                return;
            }
        }
        $requestId = $request->getHeaderLine(Constants::REQUEST_ID);
        if (empty($requestId)) {
            throw new ResponseException('',10129);
        }
        $requestTimestamp = $request->getHeaderLine(Constants::REQUEST_TIMESTAMP);
        if (empty($requestTimestamp)) {
            throw new ResponseException('',10129);
        }
//        if (abs(time() - (int)($requestTimestamp / 1000)) > 600) {
//            throw new ResponseException('',10130);
//        }
        $requestRandom = $request->getHeaderLine(Constants::REQUEST_RANDOM);
        if (in_array($router, Constants::H5_ROUTER, true)) {
            $requestLocalId = md5("{$requestTimestamp}{$requestRandom}" . env('MD5_H5_REQUEST_DATA_KEY'));
        }else{
            $requestLocalId = md5("{$router}{$requestTimestamp}{$requestRandom}" . env('MD5_REQUEST_DATA_KEY'));
        }
        if ($requestLocalId != $requestId) {
            throw new ResponseException('',10131);
        }
    }
}